package com.xinqi.modules.third.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.aliyun.oss.ServiceException;
import com.anji.captcha.model.common.ResponseModel;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import com.xinqi.common.base.response.R;
import com.xinqi.common.base.utils.json.JSON;
import com.xinqi.common.core.constant.CacheConstants;
import com.xinqi.common.core.constant.Constants;
import com.xinqi.common.core.utils.MessageUtils;
import com.xinqi.common.core.utils.SpringUtils;
import com.xinqi.common.redis.utils.RedisUtils;
import com.xinqi.common.third.sms.SmsProperties;
import com.xinqi.common.third.sms.entity.SmsResult;
import com.xinqi.common.third.sms.help.SmsHelp;
import com.xinqi.modules.third.service.SmsService;
import com.xinqi.modules.third.sms.dto.req.SendSmsCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * 短信相关 服务层实现
 * @author dzy
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class SmsServiceImpl implements SmsService {

    private final SmsProperties smsProperties;

    @Resource
    private CaptchaService captchaService;



    /**
     * 普通发送短信
     * @author dzy
     */
    @Override
    public R<String> smsCode(String phonenumber, String event) {
        //1分钟
        String key1m = CacheConstants.CAPTCHA_TIMEOUT_REDIS_KEY1M + phonenumber;
        //每个号码每分钟最多发送1次
        if (RedisUtils.hasKey(key1m)) {
            long timeout = RedisUtils.getTimeToLive(key1m);
            return R.fail("该手机号：" + phonenumber + " 剩余：" + (timeout < 0 ? timeout : timeout / 1000) + "秒后可再次进行发送！");
        }

        String key = CacheConstants.CAPTCHA_CODE_KEY + phonenumber;
        String keyTimes = CacheConstants.CAPTCHA_CODE_KEY_TIMES + phonenumber;
        String code = RandomUtil.randomNumbers(6);
        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
        RedisUtils.setCacheObject(keyTimes, 0, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
        // 验证码模板id 获取配置文件模板
        String templateId = smsProperties.getTemplate().get(event);
        if (StringUtils.isEmpty(templateId)) {
            log.error("短信模板event不存在 => {}", event);
            return R.fail("短信模板event:" + event + "不存在");
        }
        Map<String, Object> map = new HashMap<>(1);
        map.put("code", code);
        SmsHelp smsHelp = SpringUtils.getBean(SmsHelp.class);
        SmsResult result = smsHelp.send(phonenumber, map, templateId);
        if (!result.getIsSuccess()) {
            log.error("验证码短信发送异常 => {}", result);
            return R.fail("短信发送太过频繁，请稍后再发送");
        }
        log.info("验证码短信发送成功 => {}:{}:{}", phonenumber, code, JSON.stringify(result));
        // 发送成功之后往redis中存入该手机号以及验证码 并设置超时时间 1 分钟
        RedisUtils.setCacheObject(key1m, code, Duration.ofMinutes(Constants.CAPTCHA_REPEATED));
        return R.ok(result.getMessage());
    }

    /**
     * 滑动图片发送短信
     * @author dzy
     */
    @Override
    public R<String> smsCaptcha(SendSmsCode dto) {
        CaptchaVO captchaVO = new CaptchaVO();
        captchaVO.setCaptchaVerification(dto.getCaptchaVerification());
        ResponseModel response = captchaService.verification(captchaVO);
        // 验证不通过
        if (!response.isSuccess()) {
            throw new ServiceException(MessageUtils.message("captcha.code.error"));
        }
        //每个号码每分钟最多发送1次
        String key1m = CacheConstants.CAPTCHA_TIMEOUT_REDIS_KEY1M + dto.getPhonenumber();
        if (RedisUtils.hasKey(key1m)) {
            long timeout = RedisUtils.getTimeToLive(key1m);
            return R.fail("该手机号：" + dto.getPhonenumber() + " 剩余：" + (timeout < 0 ? timeout : timeout / 1000) + "秒后可再次进行发送！");
        }

        // 验证码模板id 获取配置文件模板
        String templateId = smsProperties.getTemplate().get(dto.getEvent());
        if (StringUtils.isEmpty(templateId)) {
            log.error("短信模板event不存在 => {}", dto.getEvent());
            return R.fail("短信模板event:" + dto.getEvent() + "不存在");
        }
        // 获取随机验证码
        String code = RandomUtil.randomNumbers(6);

        Map<String, Object> map = new HashMap<>(1);
        map.put("code", code);
        SmsHelp smsHelp = SpringUtils.getBean(SmsHelp.class);
        SmsResult result = smsHelp.send(dto.getPhonenumber(), map, templateId);
        if (!result.getIsSuccess()) {
            log.error("验证码短信发送异常 => {}", result);
            return R.fail("短信发送太过频繁，请稍后再发送");
        }

        // Redis 缓存验证码
        String key = CacheConstants.CAPTCHA_CODE_KEY + dto.getPhonenumber();
        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));

        // Redis 缓存验证码可用次数
        String keyTimes = CacheConstants.CAPTCHA_CODE_KEY_TIMES + dto.getPhonenumber();
        RedisUtils.setCacheObject(keyTimes, 0, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));

        // 发送成功之后往redis中存入该手机号以及验证码 并设置发送频率 1 分钟
        RedisUtils.setCacheObject(key1m, code, Duration.ofMinutes(Constants.CAPTCHA_REPEATED));

        log.info("验证码短信发送成功 => {}:{}:{}", dto.getPhonenumber(), code, JSON.stringify(result));

        return R.ok(result.getMessage());
    }

}
